/*
Copyright (c) 2025 HeZongLun
NahidaProject is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan
PSL v2.
You may obtain a copy of Mulan PSL v2 at:
		 http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
*/
#pragma once

#ifdef _WIN32
#define ExportSymbol  __declspec(dllexport)
#else
#define ExportSymbol
#endif

#include <iostream>
#include <string>
#include <cstring>
#include <iomanip>
#include <sstream>

namespace NahidaProject {
	class ExportSymbol MD5 {
	private:
		typedef unsigned char uint1;
		typedef unsigned int uint4;
		typedef unsigned long long uint8;

		uint4 md5S[64] = { 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 5,  9, 14, 20, 5,  9, 14, 20, 5,  9, 14, 20, 5,  9, 14, 20, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21 };
		uint4 md5K[64] = {
		0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
		0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
		0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
		0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
		0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
		0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
		0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
		0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
		0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
		0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
		0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05,
		0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
		0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
		0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
		0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
		0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391
		};

		uint4 LeftRotate(uint4 value, uint4 shift) { return (value << shift) | (value >> (32 - shift)); }
		uint4 F(uint4 x, uint4 y, uint4 z) { return (x & y) | (~x & z); }
		uint4 G(uint4 x, uint4 y, uint4 z) { return (x & z) | (y & ~z); }
		uint4 H(uint4 x, uint4 y, uint4 z) { return x ^ y ^ z; }
		uint4 I(uint4 x, uint4 y, uint4 z) { return y ^ (x | ~z); }

		void Transform(uint4 state[4], const uint1 block[64]);
		void PadMessage(std::string& message);
		std::string Uint4ToHex(uint4 value);

	public:
		std::string Calculate(const std::string& input);
		static std::string Hash(const std::string& input);
	};
}
